package pipeline

import (
	"MyWebcrawler/module"
	"MyWebcrawler/module/modelInternal"
	"fmt"
	"github.com/sirupsen/logrus"
)

func New(mid module.MID, itemProcessors []module.ProcessItem, CalculatorFunc module.CalculateScore) (module.Pipeline, error) {
	moduleBase, err := modelInternal.NewModuleInternal(mid, CalculatorFunc)
	if err != nil {
		return nil, err
	}
	if itemProcessors == nil {
		return nil, genPipelineErr("nil item processor list")
	}
	if len(itemProcessors) == 0 {
		return nil, genPipelineErr("empty item processor list")
	}
	var innerProcessors []module.ProcessItem
	for i, pipeline := range itemProcessors {
		if pipeline == nil {
			err := genPipelineErr(fmt.Sprintf("nil item processor[%d]", i))
			return nil, err
		}
		innerProcessors = append(innerProcessors, pipeline)
	}
	return &myPipeline{
		ModuleInternal: moduleBase,
		itemProcessors: innerProcessors,
	}, nil
}

type myPipeline struct {
	modelInternal.ModuleInternal
	itemProcessors []module.ProcessItem
	// failFast 代表处理是否需要快速失败。
	failFast bool
}

func (p *myPipeline) ItemProcessors() []module.ProcessItem {
	processors := make([]module.ProcessItem, len(p.itemProcessors))
	copy(processors, p.itemProcessors)
	return processors
}

func (p *myPipeline) Send(item module.Item) []error {
	p.ModuleInternal.IncrHandlingNumber()
	defer p.ModuleInternal.DecrHandlingNumber()
	p.ModuleInternal.IncrCalledCount()
	var errs []error
	if item == nil {
		err := genPipelineErr("nil item")
		errs = append(errs, err)
		return errs
	}
	p.ModuleInternal.IncrAcceptedCount()
	logrus.Infof("Process item %+v... \n", item)
	var currentItem = item
	for _, processor := range p.itemProcessors {
		processedItem, err := processor(currentItem)
		if err != nil {
			errs = append(errs, err)
			if p.failFast {
				break
			}
		}
		if processedItem != nil {
			currentItem = processedItem
		}
	}
	if len(errs) == 0 {
		p.ModuleInternal.IncrCompletedCount()
	}
	return errs
}

func (p *myPipeline) FailFast() bool {
	return p.failFast
}

func (p *myPipeline) SetFailFast(failFast bool) {
	p.failFast = failFast
}
